library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity uart_controller is
	port (
		d_i		: in  std_logic_vector(7 downto 0);
		tx_i 	: in  std_logic;
		reset_i	: in  std_logic;
		nclk_i	: in  std_logic;
		txd_o	: out std_logic
	);
end uart_controller;

architecture behav of uart_controller is

	component shift_reg_n
		generic(N : integer); 
		port (
			d_i     : in  std_logic_vector(N-1 downto 0);
			si_i    : in  std_logic;
			l_i     : in  std_logic;
			nclk_i  : in  std_logic;
			so_o    : out std_logic;
			q_o     : out std_logic_vector(N-1 downto 0)
		);
	end component;

	component zero_detector_n
		generic (N : integer);
		port (
			d_i 	: in  std_logic_vector(N-1 downto 0);
			zero_o  : out std_logic
		);
	end component;

	component divide_16
		port (
			nclk_i       : in  std_logic;
			reset_i		 : in  std_logic;
			nclk_div16_o : out std_logic 
		);
	end component;

	component ffd
		port (
			d_i     : in  std_logic;
			set_i   : in  std_logic;
			reset_i : in  std_logic;
			nclk_i  : in  std_logic;
			q_o     : out std_logic
		);
	end component;

	component fsm_uart
		port (
			reset_i  : in  std_logic := '0';
			txclk_i  : in  std_logic;
			start_i  : in  std_logic := '0';
			zero_i   : in  std_logic := '0';
			ti_o     : out std_logic;
			send_o   : out std_logic;
			data_o   : out std_logic;
			mode_o   : out std_logic;
			shift_o  : out std_logic
		);
	end component;

	signal s_q 		: std_logic_vector(7 downto 0);
	signal s_txclk  : std_logic;
	signal s_so		: std_logic;
	signal s_zero_d : std_logic_vector(6 downto 0);
	signal s_zero   : std_logic;
	signal s_si		: std_logic;
	signal s_mc		: std_logic;
	signal s_data	: std_logic;
	signal s_send	: std_logic;
	signal s_shift	: std_logic;

begin

	ffd_inst : ffd port map (
		d_i     => '0',
		set_i   => tx_i,
		reset_i => reset_i,
		nclk_i  => s_shift,
		q_o     => s_si
	);

	shift_reg_8_inst : shift_reg_n generic map (
		N 	   => 8
	) port map (
		d_i    => d_i,
		si_i   => s_si,
		l_i    => s_mc,
		nclk_i => s_shift,
		so_o   => s_so,
		q_o    => s_q
	);

	s_zero_d <= s_si & s_q(7 downto 2);

	zero_detector_7_inst : zero_detector_n generic map (
		N => 7
	) port map (
		d_i		=> s_zero_d, 
		zero_o	=> s_zero 
	);

	fsm_uart_inst : fsm_uart port map (
		reset_i  => reset_i,
		txclk_i  => s_txclk,
		start_i  => s_si,
		zero_i   => s_zero,
		ti_o     => open,
		send_o   => s_send,
		data_o   => s_data,
		mode_o   => s_mc,
		shift_o  => s_shift
	);

	divide_16_inst : divide_16 port map (
		nclk_i       => nclk_i,
		reset_i		 => reset_i,
		nclk_div16_o => s_txclk
	);

	txd_o <= (s_so and s_data) or s_send;

end behav;
